﻿using Action = Styx.TreeSharp.Action;
using Styx;
using Styx.Common;
using Styx.CommonBot;
using Styx.CommonBot.Routines;
using Styx.TreeSharp;
using Styx.WoWInternals;
using Styx.WoWInternals.WoWObjects;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Media;
using Styx.Pathing;
using System.Diagnostics;
using System.Threading;

namespace Kitty
{
    public partial class Main : CombatRoutine
    {
        private static readonly Stopwatch WaitTimer = new Stopwatch();
        private static Stopwatch fightTimer = new Stopwatch();
        private static Stopwatch pullTimer = new Stopwatch();
        private static Stopwatch targetCheckTimer = new Stopwatch();
        private static ulong lastGuid = 0;

        #region begin Helpers
        public string LastSpell { get; set; }
        public int LastSpelID { get; set; }
        public string LastLog { get; set; }

        #region spellID's
        public int SAVAGEROAR = 52610;
        public int RAKE = 1822;
        public int RIP = 1079;
        public int FEROCIOUSBITE = 22568;
        public int MANGLE = 33876;
        public int WEAKENEDARMOR = 113746;
        public int FAERIEFIRE = 770;
        public int FAERIESWARM = 106707;
        #endregion spellID's

        #region Buffs
        Composite createBuffs()
        {
            return new PrioritySelector(







                );
        }
        #endregion Buffs

        #region predatoryheal
        public WoWUnit GetHealTarget(double range)
        {
            return (from unit in ObjectManager.GetObjectsOfTypeFast<WoWPlayer>()
                    where ((unit.IsInMyPartyOrRaid && !unit.IsMe)
                    && !unit.IsDead
                    && !unit.IsGhost
                    && unit.IsFriendly
                    && unit.Distance <= range -1
                    && unit.InLineOfSpellSight)
                    orderby unit.HealthPercent
                    select unit).FirstOrDefault();
        }
        #endregion predatoryheal

        #region get target
        public WoWUnit FindTarget()
        {
            WoWUnit newTarget = (from o in ObjectManager.ObjectList
                                 where o is WoWUnit
                                 let unit = o.ToUnit()
                                 where (unit.Distance <= 50
                                     && unit.Attackable
                                     && unit.IsAlive
                                     && unit.IsHostile
                                     && !unit.IsCritter
                                     && !unit.IsPet
                                     && !unit.IsPetBattleCritter
                                     && !Blacklist.Contains(unit.Guid, BlacklistFlags.All))
                                 orderby unit.Distance ascending
                                 select unit
                                 ).FirstOrDefault();

            if (newTarget.Name.Length < 2)
            {
                return null;
            }
            else
            {
                newTarget.Target();
                return newTarget;
            }
        }
        Composite findNewTarget()
        {
            return new Action(ret => FindTarget());
        }
        #endregion get target

        #region spellcasting
        private delegate T Selection<out T>(object context);
        Composite Cast(string spell, string descr, int kleur, Selection<bool> reqs = null)
        {
            return
                new Decorator(
                    ret => ((reqs != null && reqs(ret)) || (reqs == null)) && SpellManager.CanCast(spell),
                    new Action(ret =>
                    {
                        SpellManager.Cast(spell, Me.CurrentTarget);
                        LogMsg(descr, kleur);
                        LastSpell = spell;
                    }
                    ));
        }
        Composite Cast(int spell, string descr, int kleur, Selection<bool> reqs = null)
        {
            return
                new Decorator(
                    ret => ((reqs != null && reqs(ret)) || (reqs == null)) && SpellManager.CanCast(spell),
                    new Action(ret =>
                    {
                        SpellManager.Cast(spell, Me.CurrentTarget);
                        LogMsg(descr, kleur);
                        LastSpelID = spell;
                    }
            ));
        }
        Composite CastBuff(string spell, string descr, int kleur, Selection<bool> reqs = null)
        {
            return
                new Decorator(
                    ret => ((reqs != null && reqs(ret)) || (reqs == null)) && SpellManager.CanCast(spell),
                    new Action(ret =>
                    {
                        SpellManager.Cast(spell, Me);
                        LogMsg(descr, kleur);
                        LastSpell = spell;
                    }
                    ));
        }
        Composite CastBuff(int spell, string descr, int kleur, Selection<bool> reqs = null)
        {
            return
                new Decorator(
                    ret => ((reqs != null && reqs(ret)) || (reqs == null)) && SpellManager.CanCast(spell),
                    new Action(ret =>
                    {
                        SpellManager.Cast(spell, Me);
                        LogMsg(descr, kleur);
                        LastSpelID = spell;
                    }
            ));
        }
        #endregion spellcasting

        #region find MotwTargets
        public WoWUnit getMotWTarget(double range)
        {
            return (from unit in ObjectManager.GetObjectsOfTypeFast<WoWPlayer>()
                    where ((unit.IsInMyPartyOrRaid || unit.IsMe)
                        && !buffExists("Mark of the Wild", unit)
                        && !buffExists("Legacy of the Emperor", unit)
                        && !buffExists("Blessing of Kings", unit)
                        && !buffExists("Embrace of the Shale Spider", unit)
                        && !unit.IsDead
                        && !unit.IsGhost
                        && unit.IsFriendly
                        && unit.Distance - unit.CombatReach - 1 <= range
                        && unit.InLineOfSpellSight)
                    select unit).FirstOrDefault();
        }
        Composite castMotW()
        {
            return new Decorator(
                new Action(ret =>
                    {
                        WoWUnit myTarget = getMotWTarget(39);

                        if (myTarget != null || myTarget.IsMe)
                        {
                            var motwChoice = CRSettings.myPrefs.motw.ToString();

                            switch (motwChoice)
                            {
                                case "Always":
                                    if (!buffExists("Mark of the Wild", myTarget)
                                        && !buffExists("Legacy of the Emperor", myTarget)
                                        && !buffExists("Blessing of Kings", myTarget)
                                        && !buffExists("Embrace of the Shale Spider", myTarget)
                                        && !Me.Mounted
                                        && Me.Shapeshift != ShapeshiftForm.FlightForm
                                        && !Me.IsFlying)
                                    {
                                        if (SpellManager.CanCast("Mark of the Wild"))
                                        {
                                            SpellManager.Cast("Mark of the Wild", myTarget);
                                            LogMsg("Mark of the Wild on " + myTarget, 0);
                                        }
                                    }
                                    break;
                                case "AlwaysButNotInCombat":
                                    if (!buffExists("Mark of the Wild", myTarget)
                                        && !buffExists("Legacy of the Emperor", myTarget)
                                        && !buffExists("Blessing of Kings", myTarget)
                                        && !buffExists("Embrace of the Shale Spider", myTarget)
                                        && !Me.Combat
                                        && !Me.Mounted
                                        && Me.Shapeshift != ShapeshiftForm.FlightForm
                                        && !Me.IsFlying)
                                    {
                                        if (SpellManager.CanCast("Mark of the Wild"))
                                        {
                                            SpellManager.Cast("Mark of the Wild", myTarget);
                                            LogMsg("Mark of the Wild on " + myTarget, 0);
                                        }
                                    }
                                    break;
                                case "NotInParty":
                                    if (!buffExists("Mark of the Wild", Me)
                                        && !Me.Mounted
                                        && Me.Shapeshift != ShapeshiftForm.FlightForm
                                        && !Me.IsFlying)
                                    {
                                        if (SpellManager.CanCast("Mark of the Wild"))
                                        {
                                            SpellManager.Cast("Mark of the Wild", Me);
                                            LogMsg("Mark of the Wild on " + StyxWoW.Me, 0);
                                        }
                                    }
                                    break;
                            }
                        }
                    }
            ));
        }
        #endregion find MotwTargets

        #region rooted
        public bool MeRooted()
        {
            WoWAuraCollection Auras = StyxWoW.Me.GetAllAuras();
            foreach (WoWAura aura in Auras)
            {
                if (!aura.IsHarmful) { return false; }

                if (aura.Spell.Mechanic == WoWSpellMechanic.Slowed
                || aura.Spell.Mechanic == WoWSpellMechanic.Dazed
                || aura.Spell.Mechanic == WoWSpellMechanic.Frozen
                || aura.Spell.Mechanic == WoWSpellMechanic.Incapacitated
                || aura.Spell.Mechanic == WoWSpellMechanic.Rooted
                || aura.Spell.Mechanic == WoWSpellMechanic.Shackled)
                {
                    return true;
                }
            }
            return false;
        }
        Composite MeIsRooted()
        {
            return new Action(ret =>
            {
                if (Me.Shapeshift == ShapeshiftForm.Cat)
                {
                    SpellManager.Cast("Cat Form", Me);
                }
                if (Me.Shapeshift == ShapeshiftForm.Bear)
                {
                    SpellManager.Cast("Bear Form", Me);
                }
                if (Me.Shapeshift == ShapeshiftForm.Normal
                    && SpellManager.HasSpell("Cat Form"))
                {
                    SpellManager.Cast("Cat Form", Me);
                }
            });
        }
        #endregion rooted

        #region between
        public bool targetDistanceBetween(int left, int right)
        {
            return Me.CurrentTarget.Location.Distance(Me.Location) >= left && Me.CurrentTarget.Location.Distance(Me.Location) <= right;
        }
        #endregion between

        #region resting
        public bool healthpercentBetween(int left, int right)
        {
            return Me.HealthPercent >= left && Me.HealthPercent <= right;
        }
        #endregion resting

        #region pull
        public float pullRange
        {
            get
            {
                string spell = CRSettings.myPrefs.spellToPull.ToString();

                switch (spell)
                {
                    case "Wrath":
                        return 35;
                    case "Moonfire":
                        return 35;
                    case "FaerieFire":
                        return 35;
                    case "FaerieSwarm":
                        return 35;
                    case "WildCharge":
                        return 35;
                    case "Rake":
                        return 3.5f;
                    case "ProwlWithPounce":
                        return 3.5f;
                    default:
                        return 3.5f;
                }
            }
        }
        Composite PullNow()
        {
            return new Action(ret =>
            {
                if (CRSettings.myPrefs.spellToPull == CRSettings.pullSpell.WildCharge
                    && Me.CurrentTarget.InLineOfSight
                    && !spellOnCooldown("Wild Charge"))
                {
                    SpellManager.Cast("Wild Charge", Me.CurrentTarget);
                    LogMsg("[Pull] Wild Charge", 5);
                    LastSpell = "Wild Charge";
                }
                if (CRSettings.myPrefs.spellToPull == CRSettings.pullSpell.Moonfire
                    && Me.CurrentTarget.InLineOfSight)
                {
                    SpellManager.Cast("Moonfire", Me.CurrentTarget);
                    LogMsg("[Pull] Moonfire", 5);
                    LastSpell = "Moonfire";
                }
                if (CRSettings.myPrefs.spellToPull == CRSettings.pullSpell.FaerieFire
                    && Me.CurrentTarget.InLineOfSight
                    && SpellManager.HasSpell("Faerie Fire")
                    && !spellOnCooldown("Faerie Fire"))
                {
                    SpellManager.Cast("Faerie Fire", Me.CurrentTarget);
                    LogMsg("[Pull] Faerie Fire", 5);
                    LastSpell = "Faerie Fire";
                }
                if (CRSettings.myPrefs.spellToPull == CRSettings.pullSpell.FaerieSwarm
                    && Me.CurrentTarget.InLineOfSight
                    && !spellOnCooldown("Faerie Swarm"))
                {
                    SpellManager.Cast("Faerie Swarm", Me.CurrentTarget);
                    LogMsg("[Pull] Faerie Swarm", 5);
                    LastSpell = "Faerie Swarm";
                }
                if (CRSettings.myPrefs.spellToPull == CRSettings.pullSpell.Wrath
                    && Me.CurrentTarget.InLineOfSight)
                {
                    SpellManager.Cast("Wrath", Me.CurrentTarget);
                    LogMsg("[Pull] Wrath", 5);
                    LastSpell = "Wrath";
                }
                if (CRSettings.myPrefs.spellToPull == CRSettings.pullSpell.Rake
                    && Me.EnergyPercent >= 35
                    && SpellManager.CanCast("Rake"))
                {
                    SpellManager.Cast("Rake", Me.CurrentTarget);
                    LogMsg("[Pull] Rake", 5);
                    LastSpell = "Rake";
                }
                if (CRSettings.myPrefs.spellToPull == CRSettings.pullSpell.ProwlWithPounce
                    && Me.EnergyPercent >= 50
                    && Me.CurrentTarget.IsWithinMeleeRange
                    && SpellManager.CanCast("Pounce"))
                {
                    SpellManager.Cast("Pounce");
                    LogMsg("[Pull] Pounce", 5);
                    LastSpell = "Pounce";
                }
                return RunStatus.Failure;
            });
        }
        #endregion pull

        #region logs
        public void LogMsg(string msg, int kleurtje)
        {
            Color kleur = Colors.Yellow;
            switch (kleurtje)
            {
                case 0:
                    kleur = Colors.Orange;
                    break;
                case 1:
                    kleur = Colors.PaleGreen;
                    break;
                case 2:
                    kleur = Colors.BlanchedAlmond;
                    break;
                case 3:
                    kleur = Colors.Yellow;
                    break;
                case 4:
                    kleur = Colors.Red;
                    break;
                case 5:
                    kleur = Colors.CornflowerBlue;
                    break;
            }
            Logging.Write(kleur, msg);
        }
        #endregion logs

        #region SavageRoar
        public bool useSavageRoar
        {
            get
            {
                return SpellManager.HasSpell("Savage Roar")
                    && (SpellManager.HasSpell("Rip")
                    && IsWoWBoss(Me.CurrentTarget)
                    && debuffTimeLeft("Rip", Me.CurrentTarget) <= 5000
                    && Me.ComboPoints >= 4)
                    
                    || (Me.ComboPoints == 0
                    && CRSettings.myPrefs.SavageryGlyph)
                    
                    || Me.ComboPoints >= 1;
            }
        }
        #endregion SavageRoar

        #region addcount
        public List<WoWUnit> NearbyUnFriendlyUnits = new List<WoWUnit>();
        public void CountAdds()
        {
            NearbyUnFriendlyUnits.Clear();

            IEnumerable<WoWUnit> units =
                ObjectManager.GetObjectsOfType<WoWUnit>(true, true).Where(
                    unit => unit != Me.CurrentTarget
                        && unit.CanSelect
                        && !unit.IsTotem
                        && unit.IsHostile
                        && !unit.IsFriendly
                        && !unit.IsCritter
                        && !unit.IsPetBattleCritter
                        && !Blacklist.Contains(unit.Guid, BlacklistFlags.All)
                        && unit.Location.Distance(Me.CurrentTarget.Location) <= 10
                        );

            foreach (WoWUnit unit in units)
            {
                NearbyUnFriendlyUnits.Add(unit);
            }
        }
        public int addCount
        {
            get
            {
                CountAdds();
                return NearbyUnFriendlyUnits.Count();
            }
        }
        #endregion AddCounting

        #region check pulltargets
        public Composite checkTargets()
        {
            return new Action(ret =>
            {
                if (Battlegrounds.IsInsideBattleground)
                {
                    if (Me.GotTarget &&
                        Me.CurrentTarget.IsPet)
                    {
                        Blacklist.Add(Me.CurrentTarget, TimeSpan.FromDays(1));
                        Me.ClearTarget();
                    }

                    if (Me.GotTarget && Me.CurrentTarget.Mounted)
                    {
                        Blacklist.Add(Me.CurrentTarget, TimeSpan.FromMinutes(1));
                        Me.ClearTarget();
                    }
                }

                if (Me.CurrentTarget.Guid != lastGuid)
                {
                    fightTimer.Reset();
                    lastGuid = Me.CurrentTarget.Guid;
                    LogMsg("Killing " + Me.CurrentTarget.Name + " at distance " + System.Math.Round(Me.CurrentTarget.Distance).ToString() + ".", 6);
                    pullTimer.Reset();
                    pullTimer.Start();

                }
                else
                {
                    if (pullTimer.ElapsedMilliseconds > 30 * 1000)
                    {
                        LogMsg("Cannot pull " + Me.CurrentTarget.Name + " now.  Blacklist for 3 minutes.", 4);
                        Styx.CommonBot.Blacklist.Add(Me.CurrentTarget.Guid, System.TimeSpan.FromMinutes(3));
                    }
                }
                return RunStatus.Failure;
            });
        }
        Composite clearMyTarget()
        {
            return
                new Action(ret => Me.ClearTarget());
        }
        #endregion checkpulltargets

        #region Kind of target
        public bool IsWoWBoss(WoWUnit mytarget)
        {

            if (gotTarget
                && Me.CurrentTarget.CreatureRank == WoWUnitClassificationType.WorldBoss)
            {
                return true;
            }
            else if (gotTarget
                && target.IsBoss(mytarget))
            {
                return true;
            }
            else if (gotTarget
                && Me.CurrentTarget.MaxHealth >= (65 * 1000000))
            {
                return true;
            }
            else if (gotTarget
                    && Me.CurrentTarget.CreatureRank == WoWUnitClassificationType.RareElite
                    && Me.CurrentTarget.MaxHealth >= (Me.MaxHealth * CRSettings.myPrefs.ElitesHealth)
                    && !Me.IsInInstance
                    && !Me.GroupInfo.IsInRaid)
            {
                return true;
            }
            else if (gotTarget
                     && Me.CurrentTarget.CreatureRank == WoWUnitClassificationType.Rare
                     && Me.CurrentTarget.MaxHealth >= (Me.MaxHealth * CRSettings.myPrefs.ElitesHealth)
                     && !Me.IsInInstance
                     && !Me.GroupInfo.IsInRaid)
            {
                return true;
            }
            else if (gotTarget
                && Me.CurrentTarget.CreatureRank == WoWUnitClassificationType.Elite
                && Me.CurrentTarget.MaxHealth >= (Me.MaxHealth * CRSettings.myPrefs.ElitesHealth)
                && !Me.IsInInstance
                && !Me.GroupInfo.IsInRaid)
            {
                return true;
            }
            else if (gotTarget
                && Me.CurrentTarget.Name.Contains("Training Dummy")
                && !Me.IsInInstance)
            {
                return true;
            }
            else if (gotTarget
                && Me.CurrentTarget.IsPlayer
                && !Me.CurrentTarget.IsFriendly)
            {
                return true;
            }
            return false;
        }

        #endregion Kind of Target

        #region movement etc .....

        public Composite moveControlls(float range)
        {
            return new Action(ret =>
            {
                if (Me.CurrentTarget.Distance > range)
                {
                    LogMsg("Moving in range " + range + " " + Me.CurrentTarget.Name, 1);
                    while (Me.CurrentTarget.Distance > range)
                    {
                        Navigator.MoveTo(StyxWoW.Me.CurrentTarget.Location);
                    }
                }
                if (!Me.CurrentTarget.InLineOfSight)
                {
                    LogMsg("Moving in line of sight " + Me.CurrentTarget.Name, 1);
                    while (!Me.CurrentTarget.InLineOfSight)
                    {
                        Navigator.MoveTo(StyxWoW.Me.CurrentTarget.Location);
                    }
                }
                if (Me.CurrentTarget != null && !Me.IsSafelyFacing(Me.CurrentTarget) && CRSettings.myPrefs.Facing)
                {
                    Me.CurrentTarget.Face();
                }
                if (CRSettings.myPrefs.Movement)
                {
                    Navigator.PlayerMover.MoveStop();
                }
                return RunStatus.Failure;
            });
        }
        #endregion movement etc ....

        #region healthstone
        Composite useHealthStone()
        {
            return new Action(ret =>
            {
                WoWItem hstone = Me.BagItems.FirstOrDefault(h => h.Entry == 5512);

                if (hstone != null && hstone.CooldownTimeLeft.TotalMilliseconds <= 0)
                {
                    hstone.Use();
                    Logging.Write(Colors.BlanchedAlmond, "Using Healthstone");
                }
                return RunStatus.Failure;
            });
        }
        #endregion healthstone

        #region flask
        Composite useAgiFlask()
        {
            return new Action(ret =>
                {
                    WoWItem flask = Me.BagItems.FirstOrDefault(h => h.Entry == 76084);

                    if (flask != null && flask.CooldownTimeLeft.TotalMilliseconds <= 0)
                    {
                        flask.Use();
                        Logging.Write(Colors.BlanchedAlmond, "Using " + flask.Name);
                    }
                    return RunStatus.Failure;
                });
        }
        #endregion flask

        #region alchemy flask
        Composite useAlchemyFlask()
        {
            return new Action(ret =>
                {
                    WoWItem alchflask = Me.BagItems.FirstOrDefault(h => h.Entry == 75525);

                    if (alchflask != null)
                    {
                        alchflask.Use();
                        Logging.Write(Colors.LightBlue, "Using Alchemist's Flask");
                    }
                });
        }
        #endregion alchemy flask

        #region can use equipped items
        private static bool CanUseEquippedItem(WoWItem item)
        {
            string itemSpell = Lua.GetReturnVal<string>("return GetItemSpell(" + item.Entry + ")", 0);
            if (string.IsNullOrEmpty(itemSpell))
            {
                return false;
            }
            return item.Usable && item.Cooldown <= 0;
        }
        #endregion can use equipped items

        #region Buff Checks

        public bool buffExists(int Buff, WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                var Results = onTarget.GetAuraById(Buff);
                if (Results != null)
                    return true;
            }
            return false;
        }

        public double buffTimeLeft(int Buff, WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                var Results = onTarget.GetAuraById(Buff);
                if (Results != null)
                {
                    if (Results.TimeLeft.TotalMilliseconds > 0)
                        return Results.TimeLeft.TotalMilliseconds;
                }
            }
            return 0;
        }

        public bool buffExists(string Buff, WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                var Results = onTarget.GetAuraByName(Buff);
                if (Results != null)
                    return true;
            }
            return false;
        }

        public double buffTimeLeft(string Buff, WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                var Results = onTarget.GetAuraByName(Buff);
                if (Results != null)
                {
                    if (Results.TimeLeft.TotalMilliseconds > 0)
                        return Results.TimeLeft.TotalMilliseconds;
                }
            }
            return 0;
        }



        public uint buffStackCount(int Buff, WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                var Results = onTarget.GetAuraById(Buff);
                if (Results != null)
                    return Results.StackCount;
            }
            return 0;
        }
        public uint buffStackCount(string Buff, WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                var Results = onTarget.GetAuraByName(Buff);
                if (Results != null)
                    return Results.StackCount;
            }
            return 0;
        }
        #endregion

        #region Cache Checks
        public IEnumerable<WoWAura> cachedAuras = new List<WoWAura>();
        public IEnumerable<WoWAura> cachedTargetAuras = new List<WoWAura>();
        public void getCachedAuras()
        {
            if (Me.CurrentTarget != null)
                cachedTargetAuras = Me.CurrentTarget.GetAllAuras();
            cachedAuras = Me.GetAllAuras();
        }
        #endregion

        #region Cooldown Checks
        private Dictionary<WoWSpell, long> Cooldowns = new Dictionary<WoWSpell, long>();
        public TimeSpan cooldownLeft(int Spell)
        {
            SpellFindResults Results;
            if (SpellManager.FindSpell(Spell, out Results))
            {
                WoWSpell Result = Results.Override ?? Results.Original;
                if (Cooldowns.TryGetValue(Result, out lastUsed))
                {
                    if (DateTime.Now.Ticks < lastUsed)
                        return Result.CooldownTimeLeft;
                    return TimeSpan.MaxValue;
                }
            }
            return TimeSpan.MaxValue;
        }
        public TimeSpan cooldownLeft(string Spell)
        {
            SpellFindResults Results;
            if (SpellManager.FindSpell(Spell, out Results))
            {
                WoWSpell Result = Results.Override ?? Results.Original;
                if (Cooldowns.TryGetValue(Result, out lastUsed))
                {
                    if (DateTime.Now.Ticks < lastUsed)
                        return Result.CooldownTimeLeft;
                    return TimeSpan.MaxValue;
                }
            }
            return TimeSpan.MaxValue;
        }
        long lastUsed;
        public int lastCast;
        public bool onCooldown(int Spell)
        {
            SpellFindResults Results;
            if (SpellManager.FindSpell(Spell, out Results))
            {
                WoWSpell Result = Results.Override ?? Results.Original;
                if (Cooldowns.TryGetValue(Result, out lastUsed))
                {
                    if (DateTime.Now.Ticks < lastUsed)
                        return Result.Cooldown;
                    return false;
                }
            }
            return false;
        }
        public bool onCooldown(string Spell)
        {
            SpellFindResults Results;
            if (SpellManager.FindSpell(Spell, out Results))
            {
                WoWSpell Result = Results.Override ?? Results.Original;
                if (Cooldowns.TryGetValue(Result, out lastUsed))
                {
                    if (DateTime.Now.Ticks < lastUsed)
                        return Result.Cooldown;
                    return false;
                }
            }
            return false;
        }
        public TimeSpan spellCooldownLeft(int Spell, bool useTracker = false)
        {
            if (useTracker)
                return cooldownLeft(Spell);
            SpellFindResults results;
            if (SpellManager.FindSpell(Spell, out results))
            {
                if (results.Override != null)
                    return results.Override.CooldownTimeLeft;
                return results.Override.CooldownTimeLeft;
            }
            return TimeSpan.MaxValue;
        }
        public TimeSpan spellCooldownLeft(string Spell, bool useTracker = false)
        {
            if (useTracker)
                return cooldownLeft(Spell);
            SpellFindResults results;
            if (SpellManager.FindSpell(Spell, out results))
            {
                if (results.Override != null)
                    return results.Override.CooldownTimeLeft;
                return results.Override.CooldownTimeLeft;
            }
            return TimeSpan.MaxValue;
        }
        public bool spellOnCooldown(int Spell, bool useTracker = false)
        {
            if (useTracker)
                return !onCooldown(Spell);
            SpellFindResults results;
            if (SpellManager.FindSpell(Spell, out results))
                return results.Override != null ? results.Override.Cooldown : results.Original.Cooldown;
            return false;
        }
        public bool spellOnCooldown(string Spell, bool useTracker = false)
        {
            if (useTracker)
                return !onCooldown(Spell);
            SpellFindResults results;
            if (SpellManager.FindSpell(Spell, out results))
                return results.Override != null ? results.Override.Cooldown : results.Original.Cooldown;
            return false;
        }
        #endregion

        #region Debuff Checks

        public bool debuffExists(int Debuff, WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                WoWAura aura = onTarget.GetAllAuras().FirstOrDefault(a => a.SpellId == Debuff && a.CreatorGuid == Me.Guid);
                if (aura != null)
                {
                    return true;
                }
            }
            return false;
        }

        public double debuffTimeLeft(int Debuff, WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                WoWAura aura = onTarget.GetAllAuras().FirstOrDefault(a =>
                    a.SpellId == Debuff
                    && a.CreatorGuid == Me.Guid);

                if (aura == null)
                {
                    return 0;
                }
                return aura.TimeLeft.TotalMilliseconds;
            }
            return 0;
        }

        public uint debuffStackCount(int Debuff, WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                WoWAura aura = onTarget.GetAllAuras().FirstOrDefault(a =>
                    a.SpellId == Debuff
                    && a.CreatorGuid == Me.Guid);

                if (aura == null)
                {
                    return 0;
                }
                return aura.StackCount;
            }
            return 0;
        }
        public bool debuffExists(string Debuff, WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                WoWAura aura = onTarget.GetAllAuras().FirstOrDefault(a => a.Name == Debuff && a.CreatorGuid == Me.Guid);
                if (aura != null)
                {
                    return true;
                }
            }
            return false;
        }

        public double debuffTimeLeft(string Debuff, WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                WoWAura aura = onTarget.GetAllAuras().FirstOrDefault(a =>
                    a.Name == Debuff
                    && a.CreatorGuid == Me.Guid);

                if (aura == null)
                {
                    return 0;
                }
                return aura.TimeLeft.TotalMilliseconds;
            }
            return 0;
        }

        public uint debuffStackCount(string Debuff, WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                WoWAura aura = onTarget.GetAllAuras().FirstOrDefault(a =>
                    a.Name == Debuff
                    && a.CreatorGuid == Me.Guid);

                if (aura == null)
                {
                    return 0;
                }
                return aura.StackCount;
            }
            return 0;
        }
        #endregion

        #region Target Checks

        internal IEnumerable<WoWUnit> attackableTargets
        {
            get { return ObjectManager.GetObjectsOfType<WoWUnit>(true, false).Where(U => U.Attackable && U.CanSelect && !U.IsFriendly && !U.IsDead && !U.IsNonCombatPet && !U.IsCritter); }
        }
        public bool gotTarget { get { return Me.GotTarget && Me.CurrentTarget != null && Me.CurrentTarget.Attackable && (!Me.CurrentTarget.IsDead && !Me.CurrentTarget.IsFriendly || isTargetDummy); } }

        public bool isTargetDummy { get { return Me.CurrentTarget.Name == "Training Dummy" || Me.CurrentTarget.Name == "Raider's Training Dummy"; } }

        internal IEnumerable<WoWUnit> nearbyTargets(WoWPoint fromLocation, double Radius)
        {
            var Hostile = attackableTargets;
            var maxDistance = Radius * Radius;
            return Hostile.Where(x => x.Location.DistanceSqr(fromLocation) < maxDistance);
        }
        public double targetDistance(WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                var Results = onTarget.DistanceSqr;
                if (Results != null)
                    return onTarget.DistanceSqr;
            }
            return 0;
        }
        public double targetHP(WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                var Results = onTarget.HealthPercent;
                if (Results != null)
                    return onTarget.HealthPercent;
            }
            return 0;
        }
        #endregion

        #region Timer Checks
        private int conv_Date2Timestam(DateTime _time)
        {
            var date1 = new DateTime(1970, 1, 1);
            DateTime date2 = _time;
            var ts = new TimeSpan(date2.Ticks - date1.Ticks);
            return (Convert.ToInt32(ts.TotalSeconds));
        }
        private uint current_life;
        private int current_time;
        private ulong guid;
        private uint first_life;
        private uint first_life_max;
        private int first_time;
        public long targetExistence(WoWUnit onTarget)
        {
            if (onTarget == null) return 0;
            if (isTargetDummy) return 9999;
            if (onTarget.CurrentHealth == 0 || onTarget.IsDead || !onTarget.IsValid || !onTarget.IsAlive)
                return 0;
            if (guid != onTarget.Guid)
            {
                guid = onTarget.Guid;
                first_life = onTarget.CurrentHealth;
                first_life_max = onTarget.MaxHealth;
                first_time = conv_Date2Timestam(DateTime.Now);
            }
            current_life = onTarget.CurrentHealth;
            current_time = conv_Date2Timestam(DateTime.Now);
            var time_diff = current_time - first_time;
            var hp_diff = first_life - current_life;
            if (hp_diff > 0)
            {
                var full_time = time_diff * first_life_max / hp_diff;
                var past_first_time = (first_life_max - first_life) * time_diff / hp_diff;
                var calc_time = first_time - past_first_time + full_time - current_time;
                if (calc_time < 1) calc_time = 99;
                var time_to_die = calc_time;
                var fight_length = full_time;
                return time_to_die;
            }
            if (hp_diff < 0)
            {
                guid = onTarget.Guid;
                first_life = onTarget.CurrentHealth;
                first_life_max = onTarget.MaxHealth;
                first_time = conv_Date2Timestam(DateTime.Now);
                return -1;
            }
            if (current_life == first_life_max)
                return 9999;
            return -1;
        }
        #endregion

        #region bugged mobs
        public Composite checkBuggedMobs()
        {
            return new Action(ret =>
            {
                if (Me.GotTarget && (!fightTimer.IsRunning || Me.CurrentTarget.Guid != lastGuid))
                {
                    fightTimer.Reset();
                    fightTimer.Start();
                    lastGuid = Me.CurrentTarget.Guid;
                }
                if (Me.CurrentTarget != null && !Me.CurrentTarget.IsPlayer &&
                            fightTimer.ElapsedMilliseconds > 40 * 1000 &&
                            Me.CurrentTarget.HealthPercent > 95)
                {
                    LogMsg(" This " + Me.CurrentTarget.Name + " is a bugged mob.  Blacklisting for 1 hour.", 4);

                    Blacklist.Add(Me.CurrentTarget.Guid, TimeSpan.FromHours(1.00));

                    SafeMove(WoWMovement.MovementDirection.Backwards, 5000);
                    Me.ClearTarget();
                    lastGuid = 0;
                }
                return RunStatus.Failure;
            });
        }

        private void SafeMove(WoWMovement.MovementDirection direction, int duration)
        {
            DateTime start = DateTime.Now;

            WoWMovement.Move(direction);

            while (IsInGame && Me.HealthPercent > 1)
            {
                Thread.Sleep(335);

                if (DateTime.Now.Subtract(start).Milliseconds < 300 || DateTime.Now.Subtract(start).Milliseconds >= duration)
                {
                    break;
                }

            }

            WoWMovement.MoveStop(direction);
        }
        private static bool IsInGame
        {
            get { return StyxWoW.IsInGame; }
        }
        #endregion bugged mobs

        #region QuestOrGrind
        public bool QuestOrGrind
        {
            get { return usedBot == "Questing" || usedBot == "Grind Bot" || usedBot == "BgBuddy" || usedBot == "DungeonBuddy"; }
        }

        #endregion QuestOrGrind

        #region useForm
        public string FormToUse
        {
            get
            {
                if ((Me.Specialization == WoWSpec.DruidGuardian || buffExists("Might of Ursoc", Me) || SwitchBearForm)
                    && SpellManager.HasSpell("Bear Form"))
                {
                    LogMsg("Bear Form", 2);
                    LastSpell = "Bear Form";
                    return "Bear Form";
                }
                LogMsg("Cat Form", 2);
                LastSpell = "Cat Form";
                return "Cat Form";
            }
        }
        #endregion useForm

        #region findtarget
        Composite ensureTarget()
        {
            return new Decorator(ret => Me.CurrentTarget == null || (Me.CurrentTarget.IsFriendly || Me.CurrentTarget.IsDead || !Me.CurrentTarget.CanSelect),
                new Action(ret =>
                {
                    WoWUnit newTarget = (from o in ObjectManager.ObjectList
                                         where o is WoWUnit
                                         let unit = o.ToUnit()
                                         where (unit.CanSelect
                                          && !unit.IsFriendly
                                          && !unit.IsCritter
                                          && !unit.IsPetBattleCritter
                                          && !Blacklist.Contains(unit.Guid, BlacklistFlags.All))
                                          || (unit.IsTargetingMeOrPet || unit.IsTargetingMyPartyMember || unit.IsTargetingMyRaidMember)
                                         orderby unit.Location.Distance(Me.Location) descending
                                         select unit)
                                   .FirstOrDefault();
                    return RunStatus.Failure;
                }));
        }
        #endregion findtarget

        #region ferocious bite
        public bool castFerociousBite
        {
            get
            {
                return SpellManager.HasSpell("Ferocious Bite")
                    && (debuffExists("Rip", Me.CurrentTarget)
                    && debuffTimeLeft("Rip", Me.CurrentTarget) >= 5000
                    && Me.ComboPoints >= 5
                    && IsWoWBoss(Me.CurrentTarget))

                    || (Me.ComboPoints >= 3
                    && (!IsWoWBoss(Me.CurrentTarget) || !SpellManager.HasSpell("Rip")));
            }
        }
        #endregion ferocious bite

        #region movement
        Composite createFacing()
        {
            return new Decorator(ret => Me.CurrentTarget != null && !Me.IsSafelyFacing(Me.CurrentTarget) && CRSettings.myPrefs.Facing,
                new Action(ret =>
                {
                    if (!Me.IsSafelyFacing(Me.CurrentTarget))
                    {
                        Me.CurrentTarget.Face();
                    }
                    return RunStatus.Failure;
                }));
        }
        Composite createLignOfSight()
        {
            return new Decorator(ret => Me.CurrentTarget != null && !Me.CurrentTarget.InLineOfSight &&  CRSettings.myPrefs.Movement,
                new Action(ret =>
                {
                    Logging.Write(inform, "Moving in lign of sight " + Me.CurrentTarget.Name);
                    while (!Me.CurrentTarget.InLineOfSight)
                    {
                        Navigator.MoveTo(StyxWoW.Me.CurrentTarget.Location);
                    }
                    return RunStatus.Failure;
                }));
        }
        Composite createMoveInRange(float range)
        {
            return new Decorator(ret => Me.CurrentTarget != null && Me.CurrentTarget.Distance > range && CRSettings.myPrefs.Movement,
                new Action(ret =>
                {
                    Logging.Write(inform, "Moving in range " + range + " " + Me.CurrentTarget.Name);
                    while (Me.CurrentTarget.Distance > range)
                    {
                        Navigator.MoveTo(StyxWoW.Me.CurrentTarget.Location);
                    }
                    return RunStatus.Failure;
                }));
        }
        Composite createStopMove(float range)
        {
            return new Decorator(ret => Me.CurrentTarget != null && Me.CurrentTarget.Distance <= 35 && CRSettings.myPrefs.Movement,
                new Action(ret =>
                {
                    if (Me.CurrentTarget.Distance <= range)
                    {
                        Navigator.PlayerMover.MoveStop();
                    }
                    return RunStatus.Failure;
                }));
        }
        #endregion movement

        #endregion einde Helpers
    }
}
